home *** CD-ROM | disk | FTP | other *** search
/ Language/OS - Multiplatform Resource Library / LANGUAGE OS.iso / gnu / patch20u.lha / patch-2.0.12u9 / util.c < prev    next >
C/C++ Source or Header  |  1992-09-14  |  10KB  |  451 lines

  1. #include "EXTERN.h"
  2. #include "common.h"
  3. #include "INTERN.h"
  4. #include "util.h"
  5. #include "backupfile.h"
  6.  
  7. void my_exit();
  8.  
  9. static char *
  10. private_strerror (errnum)
  11.      int errnum;
  12. {
  13.   extern char *sys_errlist[];
  14.   extern int sys_nerr;
  15.  
  16.   if (errnum > 0 && errnum <= sys_nerr)
  17.     return sys_errlist[errnum];
  18.   return "Unknown system error";
  19. }
  20. #define strerror private_strerror
  21.  
  22. /* Rename a file, copying it if necessary. */
  23.  
  24. int
  25. move_file(from,to)
  26. char *from, *to;
  27. {
  28.     char bakname[512];
  29.     Reg1 char *s;
  30.     Reg2 int i;
  31.     Reg3 int fromfd;
  32.  
  33.     /* to stdout? */
  34.  
  35.     if (strEQ(to, "-")) {
  36. #ifdef DEBUGGING
  37.     if (debug & 4)
  38.         say2("Moving %s to stdout.\n", from);
  39. #endif
  40.     fromfd = open(from, 0);
  41.     if (fromfd < 0)
  42.         pfatal2("internal error, can't reopen %s", from);
  43.     while ((i=read(fromfd, buf, sizeof buf)) > 0)
  44.         if (write(1, buf, i) != 1)
  45.         pfatal1("write failed");
  46.     Close(fromfd);
  47.     return 0;
  48.     }
  49.  
  50.     if (origprae) {
  51.     Strcpy(bakname, origprae);
  52.     Strcat(bakname, to);
  53.     } else {
  54. #ifndef NODIR
  55.     char *backupname = find_backup_file_name(to);
  56.     if (backupname == (char *) 0)
  57.         fatal1("out of memory\n");
  58.     Strcpy(bakname, backupname);
  59.     free(backupname);
  60. #else /* NODIR */
  61.     Strcpy(bakname, to);
  62.         Strcat(bakname, simple_backup_suffix);
  63. #endif /* NODIR */
  64.     }
  65.  
  66.     if (stat(to, &filestat) == 0) {    /* output file exists */
  67.     dev_t to_device = filestat.st_dev;
  68.     ino_t to_inode  = filestat.st_ino;
  69.     char *simplename = bakname;
  70.     
  71.     for (s=bakname; *s; s++) {
  72.         if (*s == '/')
  73.         simplename = s+1;
  74.     }
  75.     /* Find a backup name that is not the same file.
  76.        Change the first lowercase char into uppercase;
  77.        if that isn't sufficient, chop off the first char and try again.  */
  78.     while (stat(bakname, &filestat) == 0 &&
  79.         to_device == filestat.st_dev && to_inode == filestat.st_ino) {
  80.         /* Skip initial non-lowercase chars.  */
  81.         for (s=simplename; *s && !islower(*s); s++) ;
  82.         if (*s)
  83.         *s = toupper(*s);
  84.         else
  85.         Strcpy(simplename, simplename+1);
  86.     }
  87.     while (unlink(bakname) >= 0) ;    /* while() is for benefit of Eunice */
  88. #ifdef DEBUGGING
  89.     if (debug & 4)
  90.         say3("Moving %s to %s.\n", to, bakname);
  91. #endif
  92.     if (link(to, bakname) < 0) {
  93.         /* Maybe `to' is a symlink into a different file system.
  94.            Copying replaces the symlink with a file; using rename
  95.            would be better.  */
  96.         Reg4 int tofd;
  97.         Reg5 int bakfd;
  98.  
  99.         bakfd = creat(bakname, 0666);
  100.         if (bakfd < 0) {
  101.         say4("Can't backup %s, output is in %s: %s\n", to, from,
  102.              strerror(errno));
  103.         return -1;
  104.         }
  105.         tofd = open(to, 0);
  106.         if (tofd < 0)
  107.         pfatal2("internal error, can't open %s", to);
  108.         while ((i=read(tofd, buf, sizeof buf)) > 0)
  109.         if (write(bakfd, buf, i) != i)
  110.             pfatal1("write failed");
  111.         Close(tofd);
  112.         Close(bakfd);
  113.     }
  114.     while (unlink(to) >= 0) ;
  115.     }
  116. #ifdef DEBUGGING
  117.     if (debug & 4)
  118.     say3("Moving %s to %s.\n", from, to);
  119. #endif
  120.     if (link(from, to) < 0) {        /* different file system? */
  121.     Reg4 int tofd;
  122.     
  123.     tofd = creat(to, 0666);
  124.     if (tofd < 0) {
  125.         say4("Can't create %s, output is in %s: %s\n",
  126.           to, from, strerror(errno));
  127.         return -1;
  128.     }
  129.     fromfd = open(from, 0);
  130.     if (fromfd < 0)
  131.         pfatal2("internal error, can't reopen %s", from);
  132.     while ((i=read(fromfd, buf, sizeof buf)) > 0)
  133.         if (write(tofd, buf, i) != i)
  134.         pfatal1("write failed");
  135.     Close(fromfd);
  136.     Close(tofd);
  137.     }
  138.     Unlink(from);
  139.     return 0;
  140. }
  141.  
  142. /* Copy a file. */
  143.  
  144. void
  145. copy_file(from,to)
  146. char *from, *to;
  147. {
  148.     Reg3 int tofd;
  149.     Reg2 int fromfd;
  150.     Reg1 int i;
  151.     
  152.     tofd = creat(to, 0666);
  153.     if (tofd < 0)
  154.     pfatal2("can't create %s", to);
  155.     fromfd = open(from, 0);
  156.     if (fromfd < 0)
  157.     pfatal2("internal error, can't reopen %s", from);
  158.     while ((i=read(fromfd, buf, sizeof buf)) > 0)
  159.     if (write(tofd, buf, i) != i)
  160.         pfatal2("write to %s failed", to);
  161.     Close(fromfd);
  162.     Close(tofd);
  163. }
  164.  
  165. /* Allocate a unique area for a string. */
  166.  
  167. char *
  168. savestr(s)
  169. Reg1 char *s;
  170. {
  171.     Reg3 char *rv;
  172.     Reg2 char *t;
  173.  
  174.     if (!s)
  175.     s = "Oops";
  176.     t = s;
  177.     while (*t++);
  178.     rv = malloc((MEM) (t - s));
  179.     if (rv == Nullch) {
  180.     if (using_plan_a)
  181.         out_of_mem = TRUE;
  182.     else
  183.         fatal1("out of memory\n");
  184.     }
  185.     else {
  186.     t = rv;
  187.     while (*t++ = *s++);
  188.     }
  189.     return rv;
  190. }
  191.  
  192. #if defined(lint) && defined(CANVARARG)
  193.  
  194. /*VARARGS ARGSUSED*/
  195. say(pat) char *pat; { ; }
  196. /*VARARGS ARGSUSED*/
  197. fatal(pat) char *pat; { ; }
  198. /*VARARGS ARGSUSED*/
  199. pfatal(pat) char *pat; { ; }
  200. /*VARARGS ARGSUSED*/
  201. ask(pat) char *pat; { ; }
  202.  
  203. #else
  204.  
  205. /* Vanilla terminal output (buffered). */
  206.  
  207. void
  208. say(pat,arg1,arg2,arg3)
  209. char *pat;
  210. long arg1,arg2,arg3;
  211. {
  212.     fprintf(stderr, pat, arg1, arg2, arg3);
  213.     Fflush(stderr);
  214. }
  215.  
  216. /* Terminal output, pun intended. */
  217.  
  218. void                /* very void */
  219. fatal(pat,arg1,arg2,arg3)
  220. char *pat;
  221. long arg1,arg2,arg3;
  222. {
  223.     fprintf(stderr, "patch: **** ");
  224.     fprintf(stderr, pat, arg1, arg2, arg3);
  225.     my_exit(1);
  226. }
  227.  
  228. /* Say something from patch, something from the system, then silence . . . */
  229.  
  230. void                /* very void */
  231. pfatal(pat,arg1,arg2,arg3)
  232. char *pat;
  233. long arg1,arg2,arg3;
  234. {
  235.     int errnum = errno;
  236.  
  237.     fprintf(stderr, "patch: **** ");
  238.     fprintf(stderr, pat, arg1, arg2, arg3);
  239.     fprintf(stderr, ": %s\n", strerror(errnum));
  240.     my_exit(1);
  241. }
  242.  
  243. /* Get a response from the user, somehow or other. */
  244.  
  245. void
  246. ask(pat,arg1,arg2,arg3)
  247. char *pat;
  248. long arg1,arg2,arg3;
  249. {
  250.     int ttyfd;
  251.     int r;
  252.     bool tty2 = isatty(2);
  253.  
  254.     Sprintf(buf, pat, arg1, arg2, arg3);
  255.     Fflush(stderr);
  256.     write(2, buf, strlen(buf));
  257.     if (tty2) {                /* might be redirected to a file */
  258.     r = read(2, buf, sizeof buf);
  259.     }
  260.     else if (isatty(1)) {        /* this may be new file output */
  261.     Fflush(stdout);
  262.     write(1, buf, strlen(buf));
  263.     r = read(1, buf, sizeof buf);
  264.     }
  265.     else if ((ttyfd = open("/dev/tty", 2)) >= 0 && isatty(ttyfd)) {
  266.                     /* might be deleted or unwriteable */
  267.     write(ttyfd, buf, strlen(buf));
  268.     r = read(ttyfd, buf, sizeof buf);
  269.     Close(ttyfd);
  270.     }
  271.     else if (isatty(0)) {        /* this is probably patch input */
  272.     Fflush(stdin);
  273.     write(0, buf, strlen(buf));
  274.     r = read(0, buf, sizeof buf);
  275.     }
  276.     else {                /* no terminal at all--default it */
  277.     buf[0] = '\n';
  278.     r = 1;
  279.     }
  280.     if (r <= 0)
  281.     buf[0] = 0;
  282.     else
  283.     buf[r] = '\0';
  284.     if (!tty2)
  285.     say1(buf);
  286. }
  287. #endif /* lint */
  288.  
  289. /* How to handle certain events when not in a critical region. */
  290.  
  291. void
  292. set_signals(reset)
  293. int reset;
  294. {
  295. #ifndef lint
  296. #ifdef VOIDSIG
  297.     static void (*hupval)(),(*intval)();
  298. #else
  299.     static int (*hupval)(),(*intval)();
  300. #endif
  301.  
  302.     if (!reset) {
  303.     hupval = signal(SIGHUP, SIG_IGN);
  304.     if (hupval != SIG_IGN)
  305. #ifdef VOIDSIG
  306.         hupval = my_exit;
  307. #else
  308.         hupval = (int(*)())my_exit;
  309. #endif
  310.     intval = signal(SIGINT, SIG_IGN);
  311.     if (intval != SIG_IGN)
  312. #ifdef VOIDSIG
  313.         intval = my_exit;
  314. #else
  315.         intval = (int(*)())my_exit;
  316. #endif
  317.     }
  318.     Signal(SIGHUP, hupval);
  319.     Signal(SIGINT, intval);
  320. #endif
  321. }
  322.  
  323. /* How to handle certain events when in a critical region. */
  324.  
  325. void
  326. ignore_signals()
  327. {
  328. #ifndef lint
  329.     Signal(SIGHUP, SIG_IGN);
  330.     Signal(SIGINT, SIG_IGN);
  331. #endif
  332. }
  333.  
  334. /* Make sure we'll have the directories to create a file.
  335.    If `striplast' is TRUE, ignore the last element of `filename'.  */
  336.  
  337. void
  338. makedirs(filename,striplast)
  339. Reg1 char *filename;
  340. bool striplast;
  341. {
  342.     char tmpbuf[256];
  343.     Reg2 char *s = tmpbuf;
  344.     char *dirv[20];        /* Point to the NULs between elements.  */
  345.     Reg3 int i;
  346.     Reg4 int dirvp = 0;        /* Number of finished entries in dirv. */
  347.  
  348.     /* Copy `filename' into `tmpbuf' with a NUL instead of a slash
  349.        between the directories.  */
  350.     while (*filename) {
  351.     if (*filename == '/') {
  352.         filename++;
  353.         dirv[dirvp++] = s;
  354.         *s++ = '\0';
  355.     }
  356.     else {
  357.         *s++ = *filename++;
  358.     }
  359.     }
  360.     *s = '\0';
  361.     dirv[dirvp] = s;
  362.     if (striplast)
  363.     dirvp--;
  364.     if (dirvp < 0)
  365.     return;
  366.  
  367.     strcpy(buf, "mkdir");
  368.     s = buf;
  369.     for (i=0; i<=dirvp; i++) {
  370.     struct stat sbuf;
  371.  
  372.     if (stat(tmpbuf, &sbuf) && errno == ENOENT) {
  373.         while (*s) s++;
  374.         *s++ = ' ';
  375.         strcpy(s, tmpbuf);
  376.     }
  377.     *dirv[i] = '/';
  378.     }
  379.     if (s != buf)
  380.     system(buf);
  381. }
  382.  
  383. /* Make filenames more reasonable. */
  384.  
  385. char *
  386. fetchname(at,strip_leading,assume_exists)
  387. char *at;
  388. int strip_leading;
  389. int assume_exists;
  390. {
  391.     char *fullname;
  392.     char *name;
  393.     Reg1 char *t;
  394.     char tmpbuf[200];
  395.     int sleading = strip_leading;
  396.  
  397.     if (!at)
  398.     return Nullch;
  399.     while (isspace(*at))
  400.     at++;
  401. #ifdef DEBUGGING
  402.     if (debug & 128)
  403.     say4("fetchname %s %d %d\n",at,strip_leading,assume_exists);
  404. #endif
  405.     if (strnEQ(at, "/dev/null", 9))    /* so files can be created by diffing */
  406.     return Nullch;            /*   against /dev/null. */
  407.     name = fullname = t = savestr(at);
  408.  
  409.     /* Strip off up to `sleading' leading slashes and null terminate.  */
  410.     for (; *t && !isspace(*t); t++)
  411.     if (*t == '/')
  412.         if (--sleading >= 0)
  413.         name = t+1;
  414.     *t = '\0';
  415.  
  416.     /* If no -p option was given (957 is the default value!),
  417.        we were given a relative pathname,
  418.        and the leading directories that we just stripped off all exist,
  419.        put them back on.  */
  420.     if (strip_leading == 957 && name != fullname && *fullname != '/') {
  421.     name[-1] = '\0';
  422.     if (stat(fullname, &filestat) == 0 && S_ISDIR (filestat.st_mode)) {
  423.         name[-1] = '/';
  424.         name=fullname;
  425.     }
  426.     }
  427.  
  428.     name = savestr(name);
  429.     free(fullname);
  430.  
  431.     if (stat(name, &filestat) && !assume_exists) {
  432.     char *filebase = basename(name);
  433.     int pathlen = filebase - name;
  434.  
  435.     /* Put any leading path into `tmpbuf'.  */
  436.     strncpy(tmpbuf, name, pathlen);
  437.  
  438. #define try(f, a1, a2) (Sprintf(tmpbuf + pathlen, f, a1, a2), stat(tmpbuf, &filestat) == 0)
  439.     if (   try("RCS/%s%s", filebase, RCSSUFFIX)
  440.         || try("RCS/%s"  , filebase,         0)
  441.         || try(    "%s%s", filebase, RCSSUFFIX)
  442.         || try("SCCS/%s%s", SCCSPREFIX, filebase)
  443.         || try(     "%s%s", SCCSPREFIX, filebase))
  444.       return name;
  445.     free(name);
  446.     name = Nullch;
  447.     }
  448.  
  449.     return name;
  450. }
  451.